package cn.song.rabbitmq.listener;

import cn.hutool.core.date.DateTime;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.handler.annotation.Header;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;

import static cn.song.utils.FilePath.RABBITMQLOG;

/**
 * 失败队列监听器
 *
 * @author SongRenShuo
 * @date 2024/01/10
 */
@Slf4j
@Configuration
public class FailRabbitListener   {

    /**
     * 重新发布 Exchange - 交换机
     */
    public static final String RETRY_EXCHANGE = "song.direct";
    /**
     * 重新发布路由密钥 - 理由键
     */
    public static final String RETRY_EXCHANGE_KEY = "redS";

    /**
     * 修改消息失败策略
     */
    @Bean
    public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate) {

        //重新发布 -- 重试之后，将消息转发到重试失败队列，由重试失败消费者消费...
        return new RepublishMessageRecoverer(rabbitTemplate, RETRY_EXCHANGE, RETRY_EXCHANGE_KEY);
    }


    /**
     * 重试失败监听
     *
     * @param message
     * @param channel 渠道
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = RETRY_EXCHANGE, durable = "true"),
            exchange = @Exchange(value = RETRY_EXCHANGE),
            key = RETRY_EXCHANGE_KEY
    ))
    public void retryFailConsumer(Message message, Channel channel, @Header(AmqpHeaders.CONSUMER_QUEUE) String consumerQueue) throws Exception {


        String msg = new String(message.getBody(), StandardCharsets.UTF_8);

        // 输出到控制台
        log.info("[消息重试失败] 来自队列: {} 接收时间: {} 接收消息: {}", consumerQueue, DateTime.now(), msg);

        // 获取当前日期作为文件名的一部分
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String currentDate = sdf.format(new Date());

        // 定义日志文件夹路径
        String logFolderPath = RABBITMQLOG;
        // 创建日志文件夹（如果不存在）
        File logFolder = new File(logFolderPath);
        if (!logFolder.exists()) {
            boolean mkdirSuccess = logFolder.mkdirs();
            if (!mkdirSuccess) {
                log.error("无法创建日志文件夹: {}", logFolderPath);
            }
        }
        // 将消息写入到每日的文件中
        String logFilePath = logFolderPath + currentDate + "_retry_messages.log";
        // 注意这里的true代表追加模式
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(logFilePath, true))) {
            writer.newLine();
            writer.write("[消息重试失败] 来自队列: " + consumerQueue + ", 接收时间: " + DateTime.now() + ", 消息内容: " + msg);
            writer.flush();

            System.err.println("消息重试失败，已记录到文件...");
        } catch (IOException e) {
            log.error("无法将消息重试信息写入到文件中，异常: {}", e.getMessage());
        }

        // 这里根据需求决定是否继续抛出异常以进行更多次的重试
        // throw new RuntimeException("手动触发重试（如果需要）");
    }


}
